package org.fuys.coder.domain.user.service.repo.impl;

import org.fuys.coder.infrastructure.model.dto.UserPermissionDTO;
import org.fuys.coder.common.constants.RedisConstants;
import org.fuys.coder.common.constants.ResultMessageConstants;
import org.fuys.coder.common.entity.Pair;
import org.fuys.coder.common.exception.BusinessException;
import org.fuys.coder.common.util.DateUtil;
import org.fuys.coder.infrastructure.util.RedisUtil;
import org.fuys.coder.domain.audit.model.req.AuditTask;
import org.fuys.coder.domain.audit.model.vo.AuditTaskIdTypeVO;
import org.fuys.coder.domain.audit.model.vo.AuditTaskTypeVO;
import org.fuys.coder.domain.audit.service.Audit;
import org.fuys.coder.domain.auth.model.vo.UserVo;
import org.fuys.coder.domain.auth.model.vo.permission.RoleTypeVO;
import org.fuys.coder.domain.auth.service.holder.PermissionHolder;
import org.fuys.coder.common.entity.PageDTO;
import org.fuys.coder.domain.favorites.repository.IUserFavoriteRepository;
import org.fuys.coder.domain.file.service.AliYunOSSService;
import org.fuys.coder.domain.file.service.IFileService;
import org.fuys.coder.domain.user.model.req.repo.UserInfoModifyReq;
import org.fuys.coder.domain.user.model.req.repo.UserInfoSelectReq;
import org.fuys.coder.domain.user.model.req.repo.UserInfoUpdateReq;
import org.fuys.coder.domain.user.model.vo.operation.UserFollowTypeVO;
import org.fuys.coder.domain.user.model.vo.operation.UserStopVO;
import org.fuys.coder.domain.user.model.vo.repo.AuthorVO;
import org.fuys.coder.domain.user.model.vo.repo.UserStatusTypeVO;
import org.fuys.coder.domain.user.repository.IUserRepository;
import org.fuys.coder.domain.user.service.repo.IUserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @projectName: fuys-low-coder
 * @package: org.fuys.coder.domain.user.service.repo.impl
 * @className: UserServiceImpl
 * @author: WangJing
 * @description: 用户操作服务实现类
 * @date: 2024/6/30 16:34
 * @version: 1.0
 */
@Service
public class UserServiceImpl implements IUserService {

    @Resource
    private IUserRepository userRepository;

    @Resource
    private IUserFavoriteRepository userFavoriteRepository;

    @Resource
    private AliYunOSSService aliYunOSSService;

    @Resource
    private IFileService fileService;

    @Resource
    private Audit audit;

    @Override
    public void updateUserPoint(Integer userid, Integer point) {
        userRepository.updateUserPoint(userid,point);
    }

    @Override
    public int getUserPoint(Integer userId) {
        return userRepository.getUserPoint(userId);
    }

    @Override
    public void updateUserInfo(UserInfoUpdateReq req, Integer userId) {
        final UserVo userInfo = userRepository.getUserInfo(userId);
        List<String> taskList = new ArrayList<>();
        //todo 更改判断逻辑 这里也要设置防刷接口
        if (!(ObjectUtils.isEmpty(req.getUsername())||
                userInfo.getUsername().equals(req.getUsername()))) {
            taskList.add(req.getUsername());
        }
        if(!(ObjectUtils.isEmpty(req.getUsername())||
                userInfo.getIntroduce().equals(req.getIntroduce()))){
            taskList.add(req.getIntroduce());
        }

        final String fileKey = req.getAvatar();
        if(!(ObjectUtils.isEmpty(fileKey)||ObjectUtils.isEmpty(req.getFileId()))){
            //确保有效性
            if(fileService.checkKey(fileKey)){
                taskList.add("|");
                taskList.add(fileKey);
            }
        }
        AuditTask task=new AuditTask();
        task.setNeedResultHandle(true);
        task.setType(AuditTaskTypeVO.MULTIPLE.getIndex());
        task.setUserId(userId);
        task.setIdType(AuditTaskIdTypeVO.INFO.getIndex());
        task.setOtherId(Long.valueOf(userId.toString()));
        task.setTasks(taskList.toArray(new String[0]));
        task.setCallback(
                (unused)->{
                    return userRepository.updateUserInfo(req,userId);
                }
        );
        audit.doAudit(task);
    }

    @Override
    public UserVo getUserInfo(Integer userId) {
        UserVo userVo=userRepository.getUserInfo(userId);
        userVo.setAvatar(aliYunOSSService.buildUrl(Long.valueOf(userVo.getAvatar())));
        return userVo;
    }

    @Override
    public Integer getUserStatus(Integer userId) {
        return userRepository.getUserStatus(userId);
    }

    @Override
    public List<Integer> getUserFollowers(Integer userId,Integer ...types) {
        if(ObjectUtils.isEmpty(types)) {
           return userRepository.getUserFollowers(userId, UserFollowTypeVO.COMMON);
        }
        return userRepository.getUserFollowers(userId,types[0]);
    }

    @Override
    public List<Pair<Integer,Integer>> getUserNoticed(Integer userId) {
        return userRepository.getUserNoticed(userId);
    }

    @Override
    public void updateUserNoticedAuthor(List<Pair<Integer, Integer>> collect, Integer userId) {
        userRepository.updateUserNoticedAuthor(collect,userId);
    }

    @Override
    public List<AuthorVO> getUserConcernVos(Integer userId, PageDTO pageDTO) {
        final List<AuthorVO> userNoticedVos = userRepository.getUserNoticedVos(userId, pageDTO);
        if(userNoticedVos!=null){
            userNoticedVos.forEach(item->{
                item.setAvatarUrl(aliYunOSSService.buildUrl(item.getAvatar()));
            });
        }
        return userNoticedVos;
    }

    @Override
    public List<AuthorVO> getUserFollowerVos(Integer userId,Integer type,PageDTO pageDTO) {
        final List<AuthorVO> userFollowerVos = userRepository.getUserFollowerVos(userId,type,pageDTO);
        if(userFollowerVos!=null){
            userFollowerVos.forEach(item->{
                item.setAvatarUrl(aliYunOSSService.buildUrl(item.getAvatar()));
            });
        }
        return userFollowerVos;
    }

    @Override
    public List<UserVo> getUserInfoByCondition(UserInfoSelectReq selectReq) {
        final List<UserVo> userInfoByCondition = userRepository.getUserInfoByCondition(selectReq);
        if(ObjectUtils.isEmpty(userInfoByCondition)){
            return null;
        }
        userInfoByCondition.forEach(item->{
            item.setAvatar(aliYunOSSService.buildUrl(Long.parseLong(item.getAvatar())));
        });
        return userInfoByCondition;
    }

    @Override
    @Transactional
    public boolean modifyUser(UserInfoModifyReq modifyReq) {
        final Integer userId = modifyReq.getUserId();
        final UserVo userInfo = userRepository.getUserInfo(userId);
        if(ObjectUtils.isEmpty(userInfo)){
            throw new BusinessException(ResultMessageConstants.NO_USER_INFO);
        }
        final UserPermissionDTO beingOperatedPermission = PermissionHolder.getPermission(userId);
        final UserPermissionDTO operatorPermission = PermissionHolder.getPermission(modifyReq.getOperatorId());
        //判断执行操作的人的权限
        if(ObjectUtils.isEmpty(operatorPermission)){
            //无权执行 抛异常
            throw new BusinessException(ResultMessageConstants.NO_PERMISSION);
        }else{
            //有权限 检测权限等级
            if(operatorPermission.getRoleId()>= RoleTypeVO.AUDITOR.getRoleId()){
                //无权执行 抛异常
                throw new BusinessException(ResultMessageConstants.NO_PERMISSION);
            }else if(!ObjectUtils.isEmpty(beingOperatedPermission)) {
                if (operatorPermission.getRoleId() > beingOperatedPermission.getRoleId()) {
                    //等级不够或者越级 抛异常
                    throw new BusinessException(ResultMessageConstants.NO_PERMISSION);
                }
            }
        }
        try {
            //既然是后台管理 可以将一个已经注销的账号复活 因此不需要特别判断要操作的用户的状态
            //仅需要特判一种情况 什么情况呢 就是要求封禁的情况 其他的直接更改状态标识即可
            final Integer status = modifyReq.getStatus();
            if(status.equals(UserStatusTypeVO.USER_STATUS_FREEZE)){
                Date date = null;
                if(ObjectUtils.isEmpty(modifyReq.getTimeUnit())){
                    //默认封禁一天
                    date=DateUtil.addTimeFromCur(1,TimeUnit.DAYS);
                }else{
                    date=DateUtil.addTimeFromCur(modifyReq.getTime(), TimeUnit.valueOf(modifyReq.getTimeUnit().toUpperCase()));
                }
                return userRepository.freezeUser(userId,date,userInfo.getEmail());
            }
            //剩下的无论是注销还是正常 都删除stop表中的内容
            userRepository.unFreezeUser(userId,userInfo.getEmail());
            return userRepository.updateUserStatus(userId,status);
        } catch (Exception e) {
            throw new BusinessException(e.getMessage());
        }
    }

    @Override
    @Transactional
    public void unFreezeUser(Integer userId,String email) {
        userRepository.unFreezeUser(userId,email);
    }

    @Override
    public Pair<List<AuthorVO>,Long> getAuthorVOsPageByName(PageDTO pageDTO, String keywords) {
        final Pair<List<AuthorVO>, Long> authorVOList = userRepository.getAuthorVOByName(pageDTO.getPageNum(), pageDTO.getCurPage(), keywords);
        if(ObjectUtils.isEmpty(authorVOList)){
            return null;
        }
        authorVOList.getLeft().forEach(item->{
            item.setAvatarUrl(aliYunOSSService.buildUrl(item.getAvatar()));
        });
        return authorVOList;
    }

    @Override
    public String getUserNameById(Integer fromId) {
        return userRepository.getUserNameById(fromId);
    }

    @Override
    public boolean checkFavBelongUser(Integer userId, Long favId) {
        return userFavoriteRepository.checkBelong(userId,favId);
    }

    @Override
    public List<Long> getUserFavIds(Integer userId) {
        return userFavoriteRepository.getUserFavIds(userId);
    }

    @Override
    public void addUserFollower(Integer authorId, int num) {
        userRepository.updateUserFollower(authorId,num);
    }

    @Override
    public UserStopVO getStopUser(String email) {
        return userRepository.getFreezeUser(email);
    }
}
